﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System.Threading;
using System.Data.SqlClient;
using System.Data.EntityClient;
using System.Reflection;


namespace Crm2011.BusinessTransaction
{
    public class TestProcessEntity1AndDB : BaseProcess
    {
        private const string dbConnectionString = "metadata=res://*/AnotherDB.csdl|res://*/AnotherDB.ssdl|res://*/AnotherDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=192.168.211.128;initial catalog=TestDB;User ID=sa;Password=password;MultipleActiveResultSets=True\"";

        public TestProcessEntity1AndDB(ExecutionContext context, object data)
            : base(context, data)
        {

        }

        protected override void ExecuteInternal()
        {            
            var recordName ="TestProcessEntity1_" + DateTime.Now.ToString(); 

            //Creating new record in new_TestEntity1 entity
            //Using Early Bound entities generated by CrmSvcUtil.exe
            this.ExecutionContext.TracingService.Trace("Creating TestEntity1...");
            var test1 = new CrmData.new_testentity1();
            test1.new_name = recordName;
            //save new record using Plugin context
            var newGuid = ExecutionContext.Service.Create(test1);

            this.ExecutionContext.TracingService.Trace("TestEntity1 created. Id = " + newGuid.ToString());

            //creating new EF context which is used to query CRM database directly through filtered or non filtered views
            //When model is properly generated than EF is more convenient in building complex linq queries or building expressions
            using (var context = ExecutionContext.GetNewCRMEntitiesContext())
            {
                //trying to read just created record back from CRM to prove that it is not locked and accessible
                //if row is locked than Timeout exception will be thrown
                if (context.new_testentity1.Where(a => a.new_testentity1Id == newGuid).FirstOrDefault() != null)
                    this.ExecutionContext.TracingService.Trace("SUCCESS !!! Can read myself from TestEntity1");
                else
                    this.ExecutionContext.TracingService.Trace("Cannot read myself from TestEntity1");

                this.ExecutionContext.TracingService.Trace("Rows in TestEntity1: " + context.new_testentity1.Count());
            }
            
            //Creating new record in different database which may be on different server. 
            //DTC takes care about transaction
            this.ExecutionContext.TracingService.Trace("Creating custom DB record");
            using (var dbContext = new AnotherDBEntities(dbConnectionString))
            {
                var t = new Table1();
                t.Name = recordName;
                dbContext.AddToTable1(t);
                dbContext.SaveChanges();
            }
            this.ExecutionContext.TracingService.Trace("Record in Table1 created...");
          
            //next statements are purely for testing purpose
            //as we know that Data passed into entity is string we can check for a magic keyword(s) 
            //and do some action 

            //force thread to sleep so we can do some testing around the transaction
            if (Data.ToString().Contains("sleep"))
                System.Threading.Thread.Sleep(20000);

            //forse Exception so we can test rollback
            if (Data.ToString().Contains("error"))
                throw new Exception("Throwing error by request");

        }
    }
}
